home *** CD-ROM | disk | FTP | other *** search
- unit TblInfo;
-
- {$ifdef Ver80} { Delphi 1.0x }
- {$define DelphiLessThan3}
- {$endif}
- {$ifdef Ver90} { Delphi 2.0x }
- {$define DelphiLessThan3}
- {$endif}
- {$ifdef Ver93} { C++ Builder 1.0x }
- {$define DelphiLessThan3}
- {$endif}
-
- interface
-
- uses
- Classes;
-
- { Like the RTTI structures these records are the }
- { closest we can get to the internal field and method }
- { tables. Strings are stored like Delphi 1 strings }
- { (length prefixed) but have no slack space at the end. }
- { This is why all the routines exist - to return the }
- { address of things following these space-efficient strings }
-
- type
- {$ifdef Win32}
- {$LongStrings Off}
- {$endif}
- PFieldClassTable = ^TFieldClassTable;
- TFieldClassTable = packed record
- Count: Smallint;
- Classes: array[0..8191] of {$ifndef DelphiLessThan3}^{$endif}TPersistentClass;
- end;
-
- PFieldTableEntry = ^TFieldTableEntry;
- TFieldTableEntry = packed record
- Offset: Integer;
- ClassIndex: Smallint; { index into class table (multiplied by 4 in 16-bit) }
- Name: String; { No padding is stored, so physical }
- end; { amount of storage is variable }
-
- PFieldTable = ^TFieldTable;
- TFieldTable = packed record
- Count: Smallint;
- FieldClassTable: Cardinal; { offset only in 16-bit }
- {Classes: array[0..8191] of TFieldTableEntry;}
- end;
-
- PMethodTableEntry = ^TMethodTableEntry;
- TMethodTableEntry = packed record
- {$ifdef Win32}
- Size: Smallint;
- {$endif}
- Vector: Pointer;
- Name: String; { No padding is stored, so physical }
- end; { amount of storage is variable }
-
- PMethodTable = ^TMethodTable;
- TMethodTable = packed record
- Count: Smallint;
- {Entries: array[0..8191] of TMethodTableEntry;}
- end;
- {$ifdef Win32}
- {$LongStrings On}
- {$endif}
-
- function GetFieldTable(AClass: TClass): PFieldTable;
- function GetFieldTableEntry(FieldTable: PFieldTable): PFieldTableEntry;
- function GetNextFieldTableEntry(FieldTableEntry: PFieldTableEntry): PFieldTableEntry;
- function GetFieldClassTable(AClass: TClass): PFieldClassTable;
- procedure GetDataFieldNames(AClass: TClass; List: TStrings);
-
- function GetMethodTable(AClass: TClass): PMethodTable;
- function GetMethodTableEntry(MethodTable: PMethodTable): PMethodTableEntry;
- function GetNextMethodTableEntry(MethodTableEntry: PMethodTableEntry): PMethodTableEntry;
- procedure GetMethodNames(AClass: TClass; List: TStrings);
-
- implementation
-
- uses
- Forms, SysUtils, WinTypes;
-
- type
- PPointer = ^Pointer;
-
- const
- {$ifdef Ver80} { Delphi 1 }
- vmtFieldTable = -30;
- vmtMethodTable = -28;
- {$endif}
- {$ifdef Ver90} { Delphi 2}
- vmtFieldTable = -40;
- vmtMethodTable = -36;
- {$endif}
- {$ifdef Ver93} { BCB 1 }
- vmtFieldTable = -40;
- vmtMethodTable = -36;
- {$endif}
- ftClassTable = 2;
-
-
- function GetFieldTable(AClass: TClass): PFieldTable;
- begin
- {$ifdef Win32}
- Result := PPointer(Longint(AClass) + vmtFieldTable)^
- {$else}
- Result := PFieldTable(
- Ptr(PtrRec(AClass).Seg,
- PWord(Longint(AClass)+ vmtFieldTable)^))
- {$endif}
- end;
-
- function GetFieldTableEntry(FieldTable: PFieldTable): PFieldTableEntry;
- begin
- Result := nil;
- if Assigned(FieldTable) and (FieldTable^.Count > 0) then
- Result := PFieldTableEntry(Longint(FieldTable) +
- SizeOf(FieldTable^.Count) +
- SizeOf(FieldTable^.FieldClassTable))
- end;
-
- function GetNextFieldTableEntry(FieldTableEntry: PFieldTableEntry): PFieldTableEntry;
- begin
- Result := nil;
- if Assigned(FieldTableEntry) then
- Result := PFieldTableEntry(Longint(FieldTableEntry) +
- SizeOf(FieldTableEntry^.Offset) +
- SizeOf(FieldTableEntry^.ClassIndex) +
- Succ(Length(FieldTableEntry^.Name)))
- end;
-
- function GetFieldClassTable(AClass: TClass): PFieldClassTable;
- var
- FieldTable: PFieldTable;
- begin
- Result := nil;
- FieldTable := GetFieldTable(AClass);
- if Assigned(FieldTable) then
- {$ifdef Win32}
- Result := PFieldClassTable(FieldTable^.FieldClassTable)
- {$else}
- Result := PFieldClassTable(
- Ptr(PtrRec(AClass).Seg, FieldTable^.FieldClassTable))
- {$endif}
- end;
-
- procedure GetDataFieldNames(AClass: TClass; List: TStrings);
- var
- FieldTable: PFieldTable;
- FieldTableEntry: PFieldTableEntry;
- FieldClassTable: PFieldClassTable;
- Loop: Integer;
- begin
- List.BeginUpdate;
- try
- while AClass <> TForm do
- begin
- FieldTable := GetFieldTable(AClass);
- if Assigned(FieldTable) then
- begin
- FieldTableEntry := GetFieldTableEntry(FieldTable);
- FieldClassTable := GetFieldClassTable(AClass);
- if Assigned(FieldTableEntry) then
- for Loop := 1 to FieldTable^.Count do
- begin
- { Add a nice string as well as storing the address }
- { of the entry just in case it proves useful }
- List.AddObject(Format('%s: %s (offset $%x)',
- [FieldTableEntry^.Name,
- FieldClassTable^.Classes[FieldTableEntry^.ClassIndex
- {$ifdef Windows}shr 2{$endif}].ClassName,
- FieldTableEntry^.Offset]),
- TObject(FieldTableEntry));
- { Get next entry }
- FieldTableEntry := GetNextFieldTableEntry(FieldTableEntry)
- end
- end;
- { Remember form inheritance. Loop bacck until TForm is found }
- AClass := AClass.ClassParent
- end
- finally
- List.EndUpdate
- end
- end;
-
- function GetMethodTable(AClass: TClass): PMethodTable;
- begin
- {$ifdef Win32}
- Result := PPointer(Longint(AClass) + vmtMethodTable)^
- {$else}
- Result := PMethodTable(
- Ptr(PtrRec(AClass).Seg,
- PWord(Longint(AClass)+ vmtMethodTable)^))
- {$endif}
- end;
-
- function GetMethodTableEntry(MethodTable: PMethodTable): PMethodTableEntry;
- begin
- Result := nil;
- if Assigned(MethodTable) and (MethodTable^.Count > 0) then
- Result := PMethodTableEntry(Longint(MethodTable) +
- SizeOf(MethodTable^.Count))
- end;
-
- function GetNextMethodTableEntry(MethodTableEntry: PMethodTableEntry): PMethodTableEntry;
- begin
- Result := nil;
- if Assigned(MethodTableEntry) then
- Result := PMethodTableEntry(Longint(MethodTableEntry) +
- {$ifdef Win32}
- MethodTableEntry^.Size)
- {$else}
- SizeOf(MethodTableEntry^.Vector) +
- Succ(Length(MethodTableEntry^.Name)))
- {$endif}
- end;
-
- procedure GetMethodNames(AClass: TClass; List: TStrings);
- var
- MethodTable: PMethodTable;
- MethodTableEntry: PMethodTableEntry;
- Loop: Integer;
- begin
- List.BeginUpdate;
- try
- while AClass <> TForm do
- begin
- MethodTable := GetMethodTable(AClass);
- if Assigned(MethodTable) then
- begin
- MethodTableEntry := GetMethodTableEntry(MethodTable);
- if Assigned(MethodTableEntry) then
- for Loop := 1 to MethodTable^.Count do
- begin
- { Add a nice string as well as storing the address }
- { of the entry just in case it proves useful }
- List.AddObject(Format('%s (address $%p)',
- [MethodTableEntry^.Name, MethodTableEntry^.Vector]),
- TObject(MethodTableEntry));
- { Get next entry }
- MethodTableEntry := GetNextMethodTableEntry(MethodTableEntry)
- end
- end;
- { Remember form inheritance. Loop bacck until TForm is found }
- AClass := AClass.ClassParent
- end
- finally
- List.EndUpdate
- end
- end;
-
- end.
-